#include "chat.h"
#include "ui_chat.h"
#include<QHostInfo>
#include<QMessageBox>
#include<QDateTime>
#include<QProcess>
#include<QDataStream>
#include<QScrollBar>
#include<QFont>
#include<QNetworkInterface>
#include<QDebug>
#include<QFileDialog>
#include<QColorDialog>
#include<QHostAddress>
#include<QFontComboBox>
#include<QTextEdit>
#include <utility>

int Chat::num1 =0;          //
int Chat ::num2 = 0;
/*Chat::Chat(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Chat),
    server(nullptr),
    xchat(nullptr),
    is_opend(false)

{
    ui->setupUi(this);
}
*/
Chat::~Chat()
{
    is_opend = false;
    delete ui;
}



Chat::Chat(QString pasvusername, QString pasvuserip) :
    xpasusername(std::move(pasvusername)),
    xpasuserip(std::move(pasvuserip)),
    is_opend(false),
    server(nullptr),
    xchat(nullptr),
    used(false),
    ui(new Ui::Chat)
{
    ui->setupUi(this);
    ui->messageTextEdit->setFocusPolicy(Qt::StrongFocus);
    ui->textBrowser->setFocusPolicy(Qt::NoFocus);

    ui->messageTextEdit->setFocus();
    ui->messageTextEdit->installEventFilter(this);

    a = 0;
   // is_opend = false;

    ui->label->setText(tr("与%1私聊中 对方的IP：%2").arg(xpasusername)
                       .arg(xpasuserip));

    xchat = new QUdpSocket(this);
    xport = 45456;

    // 绑定端口号
    xchat->bind( QHostAddress(getIp()),xport);
    connect(xchat,SIGNAL(readyRead()),
            this,SLOT(processPendinDatagrams()));

    // 初始化服务器
    server = new TcpServer(this);
    connect(server, SIGNAL(sendFileName(QString)),
            this,SLOT(getFileName(QString)));
}

void Chat::sendMessage(messageType type, const QString& serverAddress)
{
    QByteArray data;     // 数据缓冲区
    QDataStream out(&data,QIODevice::WriteOnly);             // 数据流
    const QString localHostName = QHostInfo::localHostName();       // 本地主机名
    const QString address = getIp();                                // 本地IP地址

    // 写入数据流
    out << type << getUserName() << localHostName;
    // 根据消息类型，选择不同的写入方式
    switch (type) {
        // 服务器发送的消息
        case LeftParticipant: break;

        // 客户端发送的消息
        case Message:
        {
            used = false;
            // 如果发送的消息为空，则弹出警告对话框
            if(ui->messageTextEdit->toPlainText() =="")
            {
                QMessageBox::warning(nullptr,tr("警告"),tr("发送内容不能为空"),QMessageBox::Ok);
                return ;
            }
            else
            {
                ui->label->setText(tr("与%1私聊中 对方的IP：%2").arg(xpasusername)
                                   .arg(xpasuserip));
                message = getMessage();
                out << address << message;

               // out << address <<getMessage();
                ui->textBrowser->verticalScrollBar()->setValue(ui->textBrowser->verticalScrollBar()->maximum());
            }
            break;
        }
        // 客户端发送的文件
        case FileName:
        {
            // 如果发送的消息为空，则弹出警告对话框
            const QString clientAddresss = xpasuserip;
            out <<address << clientAddresss << fileName;
            break;
        }
        // 客户端拒绝接收文件
        case Refuse:
        {
            out << serverAddress ;
            break;
        }

        default:
            break;
        }

        qDebug() <<"num1:" << ++num1 << "ipAddress:" << address<<"\n"<<"文件"<<getMessage();
        xchat->writeDatagram(data,data.length(),QHostAddress(xpasuserip),xport);
}

void Chat::processPendinDatagrams()
{
    // 如果有数据报等待读取
    while (xchat->hasPendingDatagrams()) {
        QByteArray datagram;                // 数据缓冲区
        // 设置缓冲区大小
        datagram.resize(xchat->pendingDatagramSize());

        // 读取数据报，将其存放到缓冲区
        xchat->readDatagram(datagram.data(),datagram.size());

        // 构造数据流，用于读取缓冲区的数据
        QDataStream in(&datagram,QIODevice::ReadOnly);
        int messageTyep;                    // 消息类型
        in >> messageTyep;                  // 读取消息类型
        QString userName, localHostName, ipAddress, messagestr;

        qDebug() <<"num2:" << ++num2 << "ipAddress:" << ipAddress;

        QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");

        // 根据消息类型，选择不同的读取方式
        switch (messageTyep) {
            // 服务器发送的消息
            case Xchat: break;

            // 客户端发送的消息
            case Message:
            {
                //used = false;

                ui->label->setText(tr("与%1私聊中 对方的IP：%2").arg(xpasusername)
                                   .arg(xpasuserip));
                in >> userName >> localHostName >> ipAddress >> messagestr;
                ui->textBrowser->setTextColor(Qt::blue);
                ui->textBrowser->setCurrentFont(QFont("Times New Roman",12));
                ui->textBrowser->append("[ " +localHostName+ " ]" + time);
                qDebug() << "messagestr:"<< messagestr;
                ui->textBrowser->append(messagestr);
                this->show();
                is_opend = true;
            }

            // 客户端发送的文件
            case FileName:
            {
                // 如果没有选择保存文件的路径，则弹出警告对话框
                in >> userName >> localHostName >> ipAddress ;
                QString clientAddress,fileName;

                // 读取客户端地址和文件名
                in >> clientAddress >> fileName;

                // 如果客户端地址和本地地址相同，则弹出警告对话框
                hasPendinFile(userName,ipAddress,clientAddress,fileName);

                // 如果客户端地址和本地地址不同，则发送拒绝接收文件的消息
                this->show();

                // 如果客户端地址和本地地址不同，则发送拒绝接收文件的消息
                is_opend = true;
                break;
            }

            case Refuse:
            {
                // 如果对方拒绝接收文件，则弹出提示对话框
                in >>userName >> localHostName;
                // 如果对方拒绝接收文件，则弹出提示对话框
                QString serverAddress;
                // 读取对方地址
                in >>serverAddress;
                // 如果对方地址和本地地址相同，则弹出提示对话框
                if(getIp() == serverAddress)
                {
                    server->refused();;
                }
                break;
            }
            // 服务器发送的消息
            case LeftParticipant:
            {
                // 如果对方关闭了聊天窗口，则提示对方已经离开
                in >> userName >> localHostName;
                // 如果对方关闭了聊天窗口，则提示对方已经离开
                userLeft(userName,localHostName,time);
                // s1 = userName,s2 = time;
                // QMessageBox::information(0,tr("本次对话关闭"),tr("对方结束了对话"),QMessageBox::Ok);
                // ui->textBrowser->clear();
                // ui->messageTextEdit->clear();
                ui->~Chat();
                // close();
                break;
            }
            default: break;
        }
    }
}

QString Chat::getMessage () const
{
    QString msg = ui->messageTextEdit->toHtml();
    ui->messageTextEdit->clear();
    ui->messageTextEdit->setFocus();
    return msg;
}

void Chat::getFileName(QString name)
{
    fileName = std::move(name);
    sendMessage(FileName);
}

bool Chat::eventFilter(QObject *target, QEvent *event)
{
    // 如果事件的对象是消息输入框
    if(target == ui->messageTextEdit)
    {
        // 如果事件的类型是KeyPress事件
        if(event->type() == QEvent::KeyPress)
        {
            // 将事件转换为键盘事件
            const auto *k = dynamic_cast<QKeyEvent *> (event);
            // 如果按下了Enter键
            if(k->key() == Qt::Key_Return)
            {
                // 发送消息
                on_sendPushButton_clicked();
                return true;
            }
        }
    }
    //  将该事件交给上层对话框
    return QDialog::eventFilter(target,event);
}

void Chat :: userLeft(const QString& userName, const QString& localHostName, const QString& time)
{
    ui->textBrowser->setTextColor(Qt::gray);
    ui->textBrowser->setCurrentFont(QFont("Times New Roman",10));
    if(!used)
    {
         ui->textBrowser->append(tr("%1于%2离开!").arg(userName).arg(time));
         used = true;
    }

    ui->label->setText(tr("用户%1离开会话界面!").arg(userName));
}

QString Chat::getUserName()
{
    // 获取本地主机名
    QStringList envVariables;
    envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
                 <<"HOSTNAME.*" << "DOMAINNAME.*";
    //qDebug() << "envVariables:" << envVariables;
    // 获取本地主机名
    const QStringList environment = QProcess::systemEnvironment();
    //qDebug() << "environment:" << environment;
    // 遍历环境变量，查找本地主机名
    foreach (QString string, envVariables) {
        const int index = environment.indexOf(QRegExp(string));
        //qDebug() << "index:" <<index;
        if(index != -1)
        {
            // 获取主机名
            const QStringList stringList = environment.at(index).split('=');
            // 如果主机名不为空，则返回主机名
            if(stringList.size() == 2)
            {
                return stringList.at(1);
            }
        }
    }
    return "unknow";
}

QString Chat::getIp()
{
    // 获取本机IP地址
    QList<QHostAddress > list = QNetworkInterface::allAddresses();
    // 遍历每一个IP地址，找到第一个本机IPV4地址
    foreach (QHostAddress address, list) {
        // 如果IPV4地址，则返回该IP地址
        if(address.protocol() == QAbstractSocket::IPv4Protocol)
            return address.toString();
    }
    return nullptr;
}

void Chat::hasPendinFile(const QString& userName, const QString& serverAddress, const QString& clientAddress, const QString& fileName)
{
    // 获取本机IP地址
    const QString ipAddress = getIp();
    // 如果接收到的数据是自己发出的，就直接返回
    if(clientAddress  == ipAddress)
    {
        const int btn = QMessageBox::information(this,tr("接收文件"),
                                           tr("来自 %1 (%2)的文件:%3","是否接受")
                                           .arg(userName)
                                           .arg(serverAddress).arg(fileName),
                                           QMessageBox::Yes,QMessageBox::No);
        // 如果点击Yes按钮，则开始接收文件
        if(btn == QMessageBox::Yes)
        {
            const QString name = QFileDialog::getSaveFileName(nullptr,tr("保存文件"),fileName);
            // 如果文件名不为空，则开始接收文件
            if(!name.isEmpty())
            {
                // 创建TcpClient对象，用于接收文件
                auto *client = new TcpClient(this);
                client->setFileName(name);
                client->setHostAddress(QHostAddress(serverAddress));
                client->show();
                qDebug() << "客户端已创建与服务端的链接" ;
            }
        }
        // 如果点击No按钮，则发送拒绝接收文件的消息
        else if(btn == QMessageBox::No){
            sendMessage(Refuse,serverAddress);
            qDebug() << "severAddress:"<<serverAddress;
        }
    }
}

void Chat::on_boldToolButton_clicked(bool checked)
{
    // 如果按钮处于被按下的状态，则设置为加粗
    if(checked) {
        ui->messageTextEdit->setFontWeight(QFont::Bold);
    }
    // 如果按钮处于未被按下的状态，则设置为不加粗
    else {
        ui->messageTextEdit->setFontWeight(QFont::Normal);
    }
    ui->messageTextEdit->setFocus();
}

void Chat::on_italicToolButton_clicked(bool checked)
{
    ui->messageTextEdit->setFontItalic(checked);
    ui->messageTextEdit->setFocus();
}

void Chat::on_underToolButton_clicked(bool checked)
{
    ui->messageTextEdit->setFontUnderline(checked);
    ui->messageTextEdit->setFocus();
}

void Chat::on_colorToolButton_clicked()
{
    // 弹出颜色选择对话框
    color = QColorDialog::getColor(color,this);
    // 如果颜色有效，则设置颜色
    if(color.isValid())
    {
        ui->messageTextEdit->setTextColor(color);
        ui->messageTextEdit->setFocus();
    }
}

void Chat::on_sendToolButton_clicked()
{
    server->show();
    server->initServer();
}

void Chat::on_saveToolButton_clicked()
{
    // 保存聊天记录
    if(ui->textBrowser->document()->isEmpty())
    {
        // 如果聊天记录为空，弹出警告对话框
        QMessageBox::warning(nullptr,tr("警告"),
                             tr("聊天记录为空,无法保存!"),QMessageBox::Ok);
    }
    else
    {
        // 弹出文件保存对话框
        const QString fileName  = QFileDialog::getSaveFileName(this,tr("保存聊天记录"),tr("聊天记录"),
                                                         tr("文本(*.txt);All File(* . *)"));
        // 如果文件名为空，则返回
        if(!fileName.isEmpty())
            saveFile(fileName);
    }
}

void Chat::saveFile(const QString& fileName)
{
    // 以只写方式打开文件，如果不存在则创建
    QFile file(fileName);
    // 只写方式打开文件，如果不存在则创建
    if(!file.open(QFile::WriteOnly | QFile::Text))
    {
        // 以警告对话框，提示文件打开失败
        QMessageBox::warning(this,tr("保存文件"),tr("无法保存文件 %1:\n %2")
                             .arg(fileName)
                             .arg(file.errorString()));
        return ;
    }
    // 创建文本流对象
    QTextStream out(&file);
    // 按照一定的格式保存数据到文本流
    out << ui->textBrowser->toPlainText();
}

void Chat::on_clearToolButton_clicked()
{
    ui->textBrowser->clear();
}

void Chat::on_closePushButton_clicked()
{
    sendMessage(LeftParticipant);
    ui->textBrowser->clear();
    ui->messageTextEdit->clear();
    close();
    //ui->textBrowser->append(tr("%1于%2离开!").arg(s1).arg(s2));
    ui->label->setText(tr("与%1私聊中 对方的IP：%2").arg(xpasusername)
                       .arg(xpasuserip));
    ui->~Chat();
}

void Chat::on_sendPushButton_clicked()
{
    // 发送消息
    sendMessage(Message);
    const QString localHostName = QHostInfo::localHostName();
    const QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    ui->textBrowser->setTextColor(Qt::blue);
    ui->textBrowser->setCurrentFont(QFont("Times New Roman",12));
    ui->textBrowser->append("[" +localHostName+" ]" +time);
    ui->textBrowser->append(message);
    qDebug() << "message" <<message;
    qDebug() <<"发送的文件" <<  getMessage();
}

void Chat::closeEvent(QCloseEvent *)
{
    on_closePushButton_clicked();
}

void Chat::on_fontComboBox_currentFontChanged(const QFont &f)
{
    ui->messageTextEdit->setCurrentFont(f);
    ui->messageTextEdit->setFocus();
}

void Chat::on_comboBox_currentIndexChanged(const QString &arg1)
{
    ui->messageTextEdit->setFontPointSize(arg1.toDouble());
    ui->messageTextEdit->setFocus();
    //ui->messageTextEdit->setFontPointSize(arg1);
}
